/*
 * @Author: samples jadehh@live.com
 * @Date: 2023-12-14 11:03:04
 * @LastEditors: samples jadehh@live.com
 * @LastEditTime: 2023-12-14 11:03:04
 * @FilePath: /lib/ali_object.js
 * @Description: 阿里云盘基础类
 */
import { _ } from '../encodings/cat';

const UA =
  'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1';
const CLIENT_ID = '76917ccccd4441c39457a04f6084fb2f';
import * as Utils from '../index';
// 引用会导致出错
// import qs from "qs";
// import axios from "axios";
// import https from "https";

function getHeader() {
  const params = {};
  params['User-Agent'] = UA;
  params.Referer = 'https://www.aliyundrive.com/';
  return params;
}

class User {
  constructor() {
    this.driveId = '';
    this.userId = '';
    this.tokenType = '';
    this.accessToken = '';
    this.refreshToken = '';
  }

  static objectFrom(json_str) {
    if (_.isEmpty(json_str)) {
      return new User();
    }

    let resonse = JSON.parse(json_str),
      user = new User();
    user.driveId = resonse.default_drive_id;
    user.userId = resonse.user_id;
    user.tokenType = resonse.token_type;
    user.accessToken = resonse.access_token;
    user.refreshToken = resonse.refresh_token; // 刷新Token记录原有的Token
    return user;
  }

  getDriveId() {
    return _.isEmpty(this.driveId) ? '' : this.driveId;
  }

  getUserId() {
    return _.isEmpty(this.userId) ? '' : this.userId;
  }

  getTokenType() {
    return _.isEmpty(this.tokenType) ? '' : this.tokenType;
  }

  getAccessToken() {
    return _.isEmpty(this.accessToken) ? '' : this.accessToken;
  }

  getRefreshToken() {
    return _.isEmpty(this.refreshToken) ? '' : this.refreshToken;
  }

  setRefreshToken(refresh_token) {
    this.refreshToken = refresh_token;
  }

  getAuthorization() {
    return this.getTokenType() + ' ' + this.getAccessToken();
  }

  isAuthed() {
    return this.getTokenType().length > 0 && this.getAccessToken().length > 0;
  }

  clean() {
    this.refreshToken = '';
    this.accessToken = '';
    return this;
  }

  async save() {
    await local.set('ali', 'aliyundrive_user', this.toString());

    return this;
  }

  toString() {
    return JSON.stringify(this.toDict());
  }

  toDict() {
    return {
      default_drive_id: this.getDriveId(),
      user_id: this.getUserId(),
      token_type: this.getTokenType(),
      access_token: this.getAccessToken(),
      refresh_token: this.getRefreshToken(),
    };
  }
}

class OAuth {
  constructor() {
    this.tokenType = '';
    this.accessToken = '';
    this.refreshToken = '';
  }

  static objectFrom(json_str) {
    if (_.isEmpty(json_str)) {
      return new OAuth();
    }
    let oauth_json = JSON.parse(json_str),
      oAuth = new OAuth();
    oAuth.tokenType = oauth_json.token_type;
    oAuth.accessToken = oauth_json.access_token;
    oAuth.refreshToken = oauth_json.refresh_token;
    return oAuth;
  }

  getTokenType() {
    return _.isEmpty(this.tokenType) ? '' : this.tokenType;
  }

  getAccessToken() {
    return _.isEmpty(this.accessToken) ? '' : this.accessToken;
  }

  getRefreshToken() {
    return _.isEmpty(this.refreshToken) ? '' : this.refreshToken;
  }

  getAuthorization() {
    return this.getTokenType() + ' ' + this.getAccessToken();
  }

  clean() {
    this.refreshToken = '';
    this.accessToken = '';
    return this;
  }

  async save() {
    await local.set('ali', 'aliyundrive_oauth', this.toString());

    return this;
  }

  toString() {
    return JSON.stringify(this.toDict());
  }

  toDict() {
    return {
      token_type: this.getTokenType(),
      access_token: this.getAccessToken(),
      refresh_token: this.getRefreshToken(),
    };
  }
}

class Drive {
  constructor() {
    this.defaultDriveId = '';
    this.resourceDriveId = '';
    this.backupDriveId = '';
  }

  static objectFrom(json_str) {
    if (_.isEmpty(json_str)) {
      return new Drive();
    }
    let obj = JSON.parse(json_str),
      drive = new Drive();
    drive.defaultDriveId = obj.default_drive_id;
    drive.resourceDriveId = obj.resource_drive_id;
    drive.backupDriveId = obj.backup_drive_id;
    return drive;
  }

  getDefaultDriveId() {
    return _.isEmpty(this.defaultDriveId) ? '' : this.defaultDriveId;
  }

  getResourceDriveId() {
    return _.isEmpty(this.resourceDriveId) ? '' : this.resourceDriveId;
  }

  getBackupDriveId() {
    return _.isEmpty(this.backupDriveId) ? '' : this.backupDriveId;
  }

  clean() {
    this.defaultDriveId = '';
    this.backupDriveId = '';
    this.resourceDriveId = '';
    return this;
  }

  async save() {
    await local.set('ali', 'aliyundrive_drive', this.toString());
    return this;
  }

  toString() {
    const params = {
      default_drive_id: this.getDefaultDriveId(),
      resource_drive_id: this.getResourceDriveId(),
      backup_drive_id: this.getBackupDriveId(),
    };
    return JSON.stringify(params);
  }
}

class Code {
  constructor() {
    this.redirectUri = '';
  }

  static objectFrom(json_str) {
    if (_.isEmpty(json_str)) {
      return new Code();
    }
    let code_json = JSON.parse(json_str),
      code = new Code();
    code.redirectUri = code_json.redirectUri;
    return code;
  }

  getRedirectUri() {
    return _.isEmpty(this.redirectUri) ? '' : this.redirectUri;
  }

  getCode() {
    return this.getRedirectUri().split('code=')[1];
  }
}

class Item {
  constructor(file_id) {
    this.items = [];
    this.nextMarker = '';
    this.fileId = file_id;
    this.shareId = '';
    this.name = '';
    this.type = '';
    this.fileExtension = '';
    this.category = '';
    this.size = '';
    this.parent = '';
    this.shareToken = '';
    this.shareIndex = 0;
  }

  static objectFrom(json_str, shareToken, shareIndex) {
    if (_.isEmpty(json_str)) {
      return new Item();
    }

    let item_json = JSON.parse(json_str),
      item = new Item();

    item.nextMarker = typeof item_json.next_marker == 'undefined' ? '' : item_json.next_marker;
    item.fileId = typeof item_json.file_id == 'undefined' ? '' : item_json.file_id;
    item.shareId = typeof item_json.share_id == 'undefined' ? '' : item_json.share_id;
    item.shareToken = shareToken;
    item.name = typeof item_json.name == 'undefined' ? '' : item_json.name;
    item.type = typeof item_json.type == 'undefined' ? '' : item_json.type;
    item.fileExtension = typeof item_json.file_extension == 'undefined' ? '' : item_json.file_extension;
    item.category = typeof item_json.category == 'undefined' ? '' : item_json.category;
    item.size = typeof item_json.size == 'undefined' ? '' : item_json.size;
    item.parent = typeof item_json.parent_file_id == 'undefined' ? '' : item_json.parent_file_id;
    item.shareIndex = shareIndex;
    typeof item.items != 'undefined' &&
      Array.isArray(item_json.items) &&
      !_.isEmpty(item_json.items) &&
      item_json.items.forEach(function (x) {
        let new_item = Item.objectFrom(JSON.stringify(x), shareToken, shareIndex);
        item.items.push(new_item);
      });
    return item;
  }

  getItems() {
    return _.isEmpty(this.items) ? [] : this.items;
  }

  getNextMarker() {
    return _.isEmpty(this.nextMarker) ? '' : this.nextMarker;
  }

  getFileId() {
    return _.isEmpty(this.fileId) ? '' : this.fileId;
  }

  getShareId() {
    return _.isEmpty(this.shareId) ? '' : this.shareId;
  }

  getFileExtension() {
    return _.isEmpty(this.fileExtension) ? '' : this.fileExtension;
  }

  getName() {
    return _.isEmpty(this.name) ? '' : this.name;
  }

  getType() {
    return _.isEmpty(this.type) ? '' : this.type;
  }

  getExt() {
    return _.isEmpty(this.fileExtension) ? '' : this.fileExtension;
  }

  getCategory() {
    return _.isEmpty(this.category) ? '' : this.category;
  }

  getSize() {
    return this.size === 0 ? '' : '[' + Utils.getSize(this.size) + ']';
  }

  getParent() {
    return _.isEmpty(this.parent) ? '' : '[' + this.parent + ']';
  }

  getShareIndex() {
    return this.shareIndex;
  }

  parentFunc(item) {
    this.parent = item;
    return this;
  }

  getDisplayName(type_name) {
    let name = this.getName();
    name = name.replaceAll('玩偶哥 q 频道：【神秘的哥哥们】', '');
    if (type_name === '电视剧') {
      let replaceNameList = ['4k', '4K'];
      name = name.replaceAll('.' + this.getFileExtension(), '');
      name = name.replaceAll(' ', '').replaceAll(' ', '');
      for (const replaceName of replaceNameList) {
        name = name.replaceAll(replaceName, '');
      }
      name = Utils.getStrByRegexDefault(/\.S01E(.*?)\./, name);
      const numbers = name.match(/\d+/g);
      if (!_.isEmpty(numbers) && numbers.length > 0) {
        name = numbers[0];
      }
    }

    return name + ' ' + this.getParent() + ' ' + this.getSize();
  }
  getEpisodeUrl(type_name) {
    return this.getDisplayName(type_name) + '$' + this.getFileId() + '+' + this.shareId + '+' + this.shareToken;
  }
}

class Sub {
  constructor() {
    this.url = '';
    this.name = '';
    this.lang = '';
    this.format = '';
  }

  static create() {
    return new Sub();
  }

  setName(name) {
    this.name = name;
    return this;
  }

  setUrl(url) {
    this.url = url;
    return this;
  }

  setLang(lang) {
    this.lang = lang;
    return this;
  }

  setFormat(format) {
    this.format = format;
    return this;
  }

  setExt(ext) {
    switch (ext) {
      case 'vtt':
        return this.setFormat('text/vtt');
      case 'ass':
      case 'ssa':
        return this.setFormat('text/x-ssa');
      default:
        return this.setFormat('application/x-subrip');
    }
  }
}

async function getUserCache() {
  return await local.get('ali', 'aliyundrive_user');
}

async function getOAuthCache() {
  return await local.get('ali', 'aliyundrive_oauth');
}

function getShareId(share_url) {
  let patternAli =
    /https:\/\/www\.alipan\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?|https:\/\/www\.aliyundrive\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?/;
  let matches = patternAli.exec(share_url);
  const filteredArr = matches.filter((item) => item !== undefined);
  if (filteredArr.length > 1) {
    return matches[1];
  } else {
    return '';
  }
}

async function ali_request(url, opt) {
  let resp;
  let data;
  try {
    data = opt ? opt.data || null : null;
    const postType = opt ? opt.postType || null : null;
    const returnBuffer = opt ? opt.buffer || 0 : 0;
    const timeout = opt ? opt.timeout || 5000 : 5000;

    const headers = opt ? opt.headers || {} : {};
    if (postType === 'form') {
      headers['Content-Type'] = 'application/x-www-form-urlencoded';

      if (data != null) {
        data = qs.stringify(data, { encode: false });
      }
    }
    let respType = returnBuffer === 1 || returnBuffer === 2 ? 'arraybuffer' : undefined;
    resp = await axios(url, {
      responseType: respType,
      method: opt ? opt.method || 'get' : 'get',
      headers: headers,
      data: data,
      timeout: timeout,
      httpsAgent: https.Agent({
        rejectUnauthorized: false,
      }),
    });
    data = resp.data;

    const resHeader = {};
    for (const hks of resp.headers) {
      const v = hks[1];
      resHeader[hks[0]] = Array.isArray(v) ? (v.length === 1 ? v[0] : v) : v;
    }

    if (!returnBuffer) {
      if (typeof data === 'object') {
        data = JSON.stringify(data);
      }
    } else if (returnBuffer === 1) {
      return { code: resp.status, headers: resHeader, content: data };
    } else if (returnBuffer === 2) {
      return { code: resp.status, headers: resHeader, content: data.toString('base64') };
    }
    return { code: resp.status, headers: resHeader, content: data };
  } catch (error) {
    // await Utils.log(`请求失败,URL为:${url},失败原因为:${error}`)
    resp = error.response;
    try {
      return { code: resp.status, headers: resp.headers, content: JSON.stringify(resp.data) };
    } catch (err) {
      return { headers: {}, content: '' };
    }
  }
}

async function post(url, params) {
  url = url.startsWith('https') ? url : 'https://api.aliyundrive.com/' + url;
  let response = await postJson(url, params, getHeader());
  return response.content;
}

async function postJson(url, params, headers) {
  params['Content-Type'] = 'application/json';
  return await req(url, {
    headers: headers,
    method: 'post',
    data: params,
  });
}

export {
  UA,
  CLIENT_ID,
  OAuth,
  Code,
  Sub,
  User,
  Item,
  Drive,
  getHeader,
  getShareId,
  getOAuthCache,
  getUserCache,
  post,
  postJson,
};
